/**
 * Wrapper class for the bing geocoding service.
 * 
 * @author Kim Pommert
 * @version %I%, %G%
 */
qx.Class.define("qooxdoosample.microsoft.bing.maps.BGeoCoder",
{
	extend: qx.core.Object,
	implement: qooxdoosample.cocktail.maps.IGeoCoder,
	
	/**
	 * Class constructor.
	 * Instantiates an object of that class.
	 */
	construct: function()
	{
		this.base(arguments);
    },
    
    statics:
    {
    	/**
    	 * To use the geocoding services, a valid bing maps object
    	 * has to be present in the DOM.
    	 * This ID is used for a <div> element that is created and deleted
    	 * dynamically during the use of the service. 
    	 * A temporary map that provides the geocoding services
    	 * will be deployed in that container.
    	 */
    	TMP_MAP_CONTAINER_ID: "tmpMap"
    },
    
    properties:
    {
    	/**
    	 * Bing maps object. The map object provides all geocoding services.
    	 * This map is used temporarily to use bing's geocoding service.
    	 * It cannot be used as a map in the application.
    	 * All method calls will be converted and sent to this object.
    	 */
    	bMap:
    	{
    		nullable: true,
    		init: null,
    		check: "VEMap"
    	},
    	
    	/**
    	 * This temporary div container is used to deploy the temporary
    	 * bing maps object in the DOM.
    	 * The map must be present in a valid DOM object to use 
    	 * the geocoding services.
    	 * The container is created and removed dynamically when starting
    	 * a geocoding request to this object. It has the ID that is
    	 * described in the constant TMP_MAP_CONTAINER_ID of this class.
    	 * The div is added as a child of the <body> tag.
    	 */
    	tmpDiv:
    	{
    		nullable: true,
    		init: null,
    		check: "Object"
    	}
    },
    
    members:
    {
    	/**
    	 * Get the geographic coordinates of the address.
    	 * 
		 * @param address 	{String} The address for geocoding
		 * @param callback 	{Function} The result of the geocoding will be sent to this function
		 * @see qooxdoosample.cocktail.maps.IGeoCoder#getLatLng()
    	 */
    	getLatLng: function(address, callback)
    	{   		
    		this.__activateTmpMap();
    		this.getBMap().Find(null, address, null, null, 0, 1, false, false, false, false, 
    					function(layer, results, places, hasmore){
    			var place = places[0];
    			var res = new qooxdoosample.cocktail.util.LatLng(place.LatLong.Latitude, place.LatLong.Longitude);
    			callback(res);   		
    		});
    		this.__deactivateTmpMap();
    	},
    	
    	/**
		 * Get the coordinates and additional information about a specific address
		 * 
		 * @param address	{String} The address for geocoding
		 * @param callback	{Function} The result of the geocoding will be sent to this function
		 * @see qooxdoosample.cocktail.maps.IGeoCoder#getLocationInfo()
		 */
		getLocationInfo: function(address, callback)
		{
			this.__activateTmpMap();
			this.getBMap().Find(null, address, null, null, 0, 1, false, false, false, false, 
    					function(layer, results, places, hasmore){
    			var place = places[0];
    			
    			// set the address
    			var res = new qooxdoosample.cocktail.util.Address();
    			res.setAddress(place.Name);
    			
    			// set the LatLng object
    			var coord = new qooxdoosample.cocktail.util.LatLng(place.LatLong.Latitude, place.LatLong.Longitude);
    			res.setCoordinates(coord);
    			
    			callback(res);   		
    		});
    		
    		this.__deactivateTmpMap();
		},
		
		/**
		 * Perform reversed geocoding. 
		 * This will get the address of a specific geographical coordinate.
		 * 
		 * @param latlng	{qooxdoosample.cocktail.util.LatLng} The coordinate for reversed geocoding
		 * @param callback	{Function} The result of the reversed geocoding will be sent to this function
		 * @see qooxdoosample.cocktail.maps.IGeoCoder#getAddress()
		 */
		getAddress: function(latlng, callback)
		{
			var point = new VELatLong(latlng.getLatitude(), latlng.getLongitude());
			
			this.__activateTmpMap();			
			this.getBMap().FindLocations(point, function(locations){
				var loc = locations[0];
				
				// set the address
    			var res = new qooxdoosample.cocktail.util.Address();
    			res.setAddress(loc.Name);
    			
    			// set the LatLng object
    			var coord = new qooxdoosample.cocktail.util.LatLng(loc.LatLong.Latitude, loc.LatLong.Longitude);
    			res.setCoordinates(coord);
    			
    			callback(res);  
			});
			this.__deactivateTmpMap();
		},
		
		/**
		 * If the temporary bing maps object is not yet created, it will be
		 * set here first. The temporary div container for the map is created
		 * and added as a child of the <body> tag.
		 * 
		 * This method must be called at the beginning of every geocoding
		 * request to the temporary map object, as that has to be
		 * deployed in a valid div container of the DOM!
		 */
		__activateTmpMap: function()
		{
			/*
			 * Bing Maps needs a valid Map object in a div container
			 * to provide the geocoding services
			 * 
			 * -> temporary div will be created and after geocoding removed from DOM
			 */
			if(this.getTmpDiv() == null){
				this.setTmpDiv(document.createElement('div'));
    			this.getTmpDiv().setAttribute('id', this.self(arguments).TMP_MAP_CONTAINER_ID);
			}
    		document.getElementsByTagName("body")[0].appendChild(this.getTmpDiv());
    		
    		if(this.getBMap() == null){
    			this.setBMap(new VEMap(this.self(arguments).TMP_MAP_CONTAINER_ID));
				this.getBMap().LoadMap();
				this.getBMap().HideDashboard();
    		}
		},
		
		/**
		 * Removes the temporary div container from the DOM.
		 * 
		 * This method must be called after every geocoding request
		 * to remove the temporary map from the DOM.
		 */
		__deactivateTmpMap: function()
		{
			document.getElementsByTagName("body")[0].removeChild(this.getTmpDiv());
		}
    }
});